﻿using System;
using RiskMan.DataClass.Models.Sterling;
using RiskMan.Config;
using RiskMan.DataClass.Models.NotBasModels;
using TheControllerRisk.Settings;

namespace RiskMan.Views.Streling
{


    class SterlingLogik
    {
        private DataClass.Data data;
        private MainWindow mainWindow;
        private SterlingItem SItem;
        double _ttpLast;
        string _classcode;
        int _accuraccy;

        public SterlingLogik()
        { }
        public SterlingLogik(MainWindow mainWindow, SterlingItem sItem)
        {
            this.mainWindow = mainWindow;
            this.data = mainWindow.DataProvider;
            this.SItem = sItem;
        }

        public void Start(SterlingItem SItem)
        {
            //цена последней сделки
            _ttpLast = mainWindow.DataProvider.GetLastPrice(SItem.Instrument);
            _classcode = mainWindow.DataProvider.GetClasscode(SItem.Instrument);
            _accuraccy = mainWindow.DataProvider.GetAccuraccy(SItem.Instrument);
            SItem.LastPrice = _ttpLast;

            return;
            // время работы
            if (new WorkingTimeClass(SItem.Account).IsWork() == true)
            {
                if (SItem.TradeList == null || SItem.TradeList.Count == 0)
                {
                    if (DateTime.Now < SItem.TimeCancelRepeatOpen && DateTime.Now < SItem.TimeKillAndClosePoz)
                    {
                        OpenStopOrderNew(SItem);

                    }
                }

                if (SItem.TradeList != null && SItem.TradeList.Count != 0)
                {
                    GetStatusAndBalanceStopLimit(SItem);


                    //GetStatusAndBalance(lvItem);
                    SItem.CurPosition = 0;
                    foreach (var item in SItem.TradeList)
                    {
                        if (item.OrderFromStopLimitOpenBalance > 0)
                        {
                            if (SItem.Operation == cfg.Buy)
                                SItem.CurPosition = SItem.CurPosition + item.OrderFromStopLimitOpenBalance;
                            else
                                SItem.CurPosition = SItem.CurPosition - item.OrderFromStopLimitOpenBalance;
                        }


                    }

                    //Выставление стопй-заявок на закрытие позиций
                    if (SItem.TradeList.Count > 0)
                    {
                        if (SItem.CurPosition != 0 && (SItem.TradeList[0].StopLimitCloseStatusOrder == null || (SItem.TradeList[0].StopLimitCloseStatusOrder == cfg.Cancel && SItem.TradeList[0].CloseStatusOrder == cfg.Cancel)))
                            CloseStopOrder(SItem);
                        if (SItem.TradeList[0].StopLimitCloseStatusOrder != null)
                        {
                            GetStatusAndBalanceStopLimitClose(SItem);
                        }

                    }
                }

            }
        }


        /// <summary>
        /// Выставляем заявку на отрткрытие позиции при горизонтальном уровне
        /// </summary>
        /// <param name="ldItem"></param>
        private void OpenStopOrderNew(SterlingItem Item)
        {

            if (Item.TradeList == null)
                Item.TradeList = new System.Collections.ObjectModel.ObservableCollection<TradesOpen>();

            if (Item.Operation == cfg.Buy && Item.LastPrice != 0)
                AddOStoprderOpenTotradeList(Item, _classcode, Math.Round(SItem.PriceOpen), Item.Operation == "Купля" ? 'B' : 'S');

            if (Item.Operation == cfg.Sell && Item.LastPrice != 0)
                AddOStoprderOpenTotradeList(Item, _classcode, Math.Round(SItem.PriceOpen), Item.Operation == "Купля" ? 'B' : 'S');
        }

        /// <summary>
        /// выставляем заявкку на откртыие позиции и записываем в лист
        /// </summary>
        /// <param name="ldItem"></param>
        /// <param name="Classcode"></param>
        /// <param name="PriceOpen"></param>
        /// <param name="oper"></param>
        private void AddOStoprderOpenTotradeList(SterlingItem ldItem, string Classcode, double PriceOpen, char oper)
        {
            TradesOpen tradesOpen = new TradesOpen();
            tradesOpen.OpenDate = DateTime.Now;

            if (Classcode != "SPBFUT")
                tradesOpen.StopLimitOpenID = mainWindow.Terminals.SentStopOrder(ldItem.Account, ldItem.ClientCode, oper,
                    PriceOpen, PriceOpen+20, ldItem.Quantity, ldItem.Instrument, Classcode);

            else
                tradesOpen.StopLimitOpenID = mainWindow.Terminals.SentStopOrder(ldItem.Account, ldItem.ClientCode, oper,
                    PriceOpen, PriceOpen+20, ldItem.Quantity, ldItem.Instrument, Classcode);

            if (oper == 'B')
            {
                tradesOpen.StopLimitOpenOperation = "Купля";
            }
            else
            {
                tradesOpen.StopLimitOpenOperation = "Продажа";
            }

            tradesOpen.StopLimitOpenQuantity = ldItem.Quantity;
            tradesOpen.OrderFromStopLimitOpenQuantity = ldItem.Quantity;
            tradesOpen.StopLimitOpenStatusOrder = cfg.Unknown;
            tradesOpen.StopLimitOpenDate = DateTime.Now;
            ldItem.TradeList.Add(tradesOpen);
            ldItem.CurNumberOfAttempt += 1;

        }

        /// <summary>
        /// Выставление стоп-заявок на закрытие позиции
        /// </summary>
        /// <param name="lvItem"></param>
        private void CloseStopOrder(SterlingItem lvItem)
        {
            //находимся в лонге

            double StopPrice = GetStopPrice(lvItem);


            if (Properties.Settings.Default.adapter == cfg.adapterQuik)
                lvItem.TradeList[0].StopLimitCloseID = mainWindow.Terminals.SentStopOrder( lvItem.Account, lvItem.ClientCode, lvItem.Operation == "Купля" ? 'S' : 'B',StopPrice, StopPrice-20,
                    Math.Abs(lvItem.CurPosition), lvItem.Instrument, _classcode);

            if (lvItem.Operation == "Купля")
            {
                lvItem.TradeList[0].StopLimitCloseOperation = cfg.Sell;
                lvItem.TradeList[0].StopLimitClosePrice = StopPrice;
            }
            else
            {
                lvItem.TradeList[0].StopLimitCloseOperation = cfg.Buy;
                lvItem.TradeList[0].StopLimitClosePrice = StopPrice;
            }

            lvItem.TradeList[0].StopLimitCloseQuantity = lvItem.CurPosition;
            lvItem.TradeList[0].StopLimitCloseStatusOrder = cfg.Unknown;
            lvItem.TradeList[0].StopLimitCloseDate = DateTime.Now;

        }


        /// <summary>
        /// Рассчитваем цену активации в зависимости от выбарнного типа расчета
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private double GetStopPrice(SterlingItem item)
        {
            double result = 0;
            if (item.TradeList[0].StopLimitOpenStatusOrder != null && item.TradeList[0].OrderFromStopLimitOpenStatusOrder == null && item.TradeList[0].OrderFromStopLimitCloseStatusOrder == null)
                result = item.PriceOpen;

            if (item.TradeList[0].StopLimitOpenStatusOrder == cfg.Performed &&
                item.TradeList[0].OrderFromStopLimitOpenStatusOrder == cfg.Performed)
            {
                if (item.Operation == cfg.Buy)
                {
                    if (item.NumberBreakevenStop == 0)
                        result = item.PriceOpen*(1 - item.InitialStop/100);

                    if (item.LastPrice >= item.PriceOpen*(1 + item.Breakeven/100))
                        item.NumberBreakevenStop = 1;

                    if (item.NumberBreakevenStop == 1)
                        result = item.PriceOpen*(1 + item.Breakeven/100);

                    if (item.LastPrice >= item.PriceOpen*(1 + item.ChangePrice2/100))
                        item.NumberBreakevenStop = 2;

                    if (item.NumberBreakevenStop == 1)
                        result = item.PriceOpen*(1 + item.MoveStop/100);
                }
                if (item.Operation == cfg.Sell)
                {
                    if (item.NumberBreakevenStop == 0)
                        result = item.PriceOpen * (1 + item.InitialStop / 100);

                    if (item.LastPrice >= item.PriceOpen * (1 - item.Breakeven / 100))
                        item.NumberBreakevenStop = 1;

                    if (item.NumberBreakevenStop == 1)
                        result = item.PriceOpen * (1 - item.Breakeven / 100);

                    if (item.LastPrice >= item.PriceOpen * (1 - item.ChangePrice2 / 100))
                        item.NumberBreakevenStop = 2;

                    if (item.NumberBreakevenStop == 1)
                        result = item.PriceOpen * (1 - item.MoveStop / 100);
                }
            }


            
            return Math.Round(result, _accuraccy);
        }

        /// <summary>
        /// блок проверки стоп-заявок статуса и баланса
        /// </summary>
        /// <param name="ld"></param>
        public void GetStatusAndBalanceStopLimit(SterlingItem ld)
        {
            try
            {
                var orderMassiv = data.GetOrderListAll(ld.Account, ld.ClientCode);
                var StopLimitMassiv = data.GetStopOrderList(ld.Account, ld.ClientCode);


                #region Проверка по цене для стопа часть 1 из 3

                double StopPrice = GetStopPrice(ld);

                #endregion



                //Проверка исполнения заявки типа связанная заявка
                for (int i = 0; i < ld.TradeList.Count; i++)
                {
                    if (ld.TradeList.Count == 0)
                        break;

                    #region стоп лимит
                    foreach (var item2 in StopLimitMassiv)
                    {
                        //проверка статусов на изменение заявок на открытие пока балансе не равен выставленному числу
                        if (item2.TID == ld.TradeList[i].StopLimitOpenID && ld.TradeList[i].StopLimitOpenStatusOrder != cfg.Cancel && ld.TradeList[i].StopLimitOpenStatusOrder != cfg.Performed)
                        {
                            ld.TradeList[i].StopLimitOpenNumberOrder = item2.Number;
                            ld.TradeList[i].StopLimitOpenStatusOrder = item2.Status;
                        }
                        if (item2.TID == ld.TradeList[i].StopLimitOpenID)
                        {
                            if (ld.TradeList[i].StopLimitOpenStatusOrder != cfg.Unknown || String.IsNullOrEmpty(ld.TradeList[i].StopLimitOpenResult))
                                ld.TradeList[i].StopLimitOpenResult = item2.Result;
                            //если стоп-заявка отвергнута системой выставляем еще раз
                            if (ld.TradeList[i].StopLimitOpenResult == cfg.RemoveFormTs)
                                ld.TradeList[i].StopLimitOpenStatusOrder = null;
                            //определяем номер заявки выставленной в систему при активации стоп-заявки
                            if (ld.TradeList[i].StopLimitOpenResult == cfg.AddToTs)
                                ld.TradeList[i].StopLimitOpenNumberLinkidOrder = item2.NumberOrder;
                        }

                        #region Проверка по цене для стопа часть 2 из 3

                        //if (item2.TID == ld.TradeList[i].StopLimitCloseID && ld.TradeList[i].StopLimitCloseStatusOrder == cfg.Active)
                        //{
                        //    //Проверка по цене активации
                        //    if (ld.TimeKillStopOrder.TimeOfDay + new TimeSpan(0, 0, 10) <= DateTime.Now.TimeOfDay)
                        //    {
                        //        if (item2.StopPrice != StopPrice)
                        //        {
                        //            mainWindow.Terminals.CancelStopOrder(item2.Number, ld.Instrument, Classcode, ld.Account, ld.ClientCode);
                        //            ld.TimeKillStopOrder = DateTime.Now;
                        //        }
                        //    }
                        //}


                        #endregion

                    }

                    //по прошествии 10 или уже другая дата секунд стоп-заявку можно снять снова, если не получилось с первого раза
                    if ((ld.TradeList[0].OrderFromStopLimitOpenDate.TimeOfDay + new TimeSpan(0, 0, 10) <= DateTime.Now.TimeOfDay || ld.TradeList[0].OrderFromStopLimitOpenDate.Date != DateTime.Now.Date) && ld.TradeList[0].OrderFromStopLimitOpenDate != new DateTime())
                    {
                        ld.TradeList[0].OrderFromStopLimitOpenDate = new DateTime();
                    }

                    //если в течении 10 секунд стоп-заявка не появилась в системе удалить ее, или ее сняли в ручном формате и не было исполнения, или удаляетс из списка если заявка не определена и уже ее смотрят в другом дне. На закрытие позиции
                    if ((ld.TradeList[i].StopLimitOpenDate.TimeOfDay + new TimeSpan(0, 0, 10) <= DateTime.Now.TimeOfDay && ld.TradeList[i].StopLimitOpenStatusOrder == cfg.Unknown)
                        || (ld.TradeList[i].StopLimitOpenDate.Date != DateTime.Now.Date && (ld.TradeList[i].StopLimitOpenStatusOrder == cfg.Unknown)))
                    {
                        ld.TradeList[i].StopLimitOpenStatusOrder = null;
                        ld.TradeList.Remove(ld.TradeList[i]);
                        i--;
                        break;
                    }
                    #endregion


                    //провереям заявки на выставление
                    if (ld.TradeList[i].StopLimitOpenStatusOrder != null && ld.TradeList[i].StopLimitOpenStatusOrder != cfg.Unknown)
                    {
                        foreach (var item2 in orderMassiv)
                        {

                            if (ld.TradeList[i].StopLimitOpenResult == cfg.AddToTs)
                            {
                                if (ld.TradeList[i].StopLimitOpenNumberLinkidOrder == item2.Number && ld.TradeList[i].OrderFromStopLimitOpenStatusOrder == null)
                                {
                                    ld.TradeList[i].OrderFromStopLimitOpenStatusOrder = item2.Status;
                                    ld.TradeList[i].OrderFromStopLimitOpenNumberOrder = item2.Number;
                                    ld.TradeList[i].OrderFromStopLimitOpenID = item2.TID;
                                    if (ld.TradeList[i].OrderFromStopLimitOpenQuantity == item2.Count)
                                        ld.TradeList[i].OrderFromStopLimitOpenBalance = item2.Count - item2.OstCount;
                                    else
                                    {
                                        //если заявка снята либо в конце сеесии либо врунчую и надо выставляться на меньший объем
                                        if (ld.TradeList[i].OrderFromStopLimitOpenQuantity > ld.TradeList[i].OrderFromStopLimitOpenBalance + item2.OstCount)
                                            ld.TradeList[i].OrderFromStopLimitOpenBalance = ld.TradeList[i].OrderFromStopLimitOpenQuantity - item2.OstCount;
                                        if (ld.TradeList[i].OrderFromStopLimitOpenQuantity == ld.TradeList[i].OrderFromStopLimitOpenBalance + item2.OstCount && item2.OstCount == 0)
                                            ld.TradeList[i].OrderFromStopLimitOpenBalance = ld.TradeList[i].OrderFromStopLimitOpenQuantity;
                                    }
                                }

                                if (ld.TradeList[i].OrderFromStopLimitOpenStatusOrder != null &&
                                    ld.TradeList[i].OrderFromStopLimitOpenID == item2.TID &&
                                    ld.TradeList[i].StopLimitOpenNumberLinkidOrder == item2.Number)
                                {
                                    ld.TradeList[i].OrderFromStopLimitOpenStatusOrder = item2.Status;
                                    if (ld.TradeList[i].OrderFromStopLimitOpenQuantity == item2.Count)
                                        ld.TradeList[i].OrderFromStopLimitOpenBalance = item2.Count - item2.OstCount;
                                    else
                                    {
                                        //если заявка снята либо в конце сеесии либо врунчую и надо выставляться на меньший объем
                                        if (ld.TradeList[i].OrderFromStopLimitOpenQuantity > ld.TradeList[i].OrderFromStopLimitOpenBalance + item2.OstCount)
                                            ld.TradeList[i].OrderFromStopLimitOpenBalance = ld.TradeList[i].OrderFromStopLimitOpenQuantity - item2.OstCount;
                                        if (ld.TradeList[i].OrderFromStopLimitOpenQuantity == ld.TradeList[i].OrderFromStopLimitOpenBalance + item2.OstCount && item2.OstCount == 0)
                                            ld.TradeList[i].OrderFromStopLimitOpenBalance = ld.TradeList[i].OrderFromStopLimitOpenQuantity;
                                    }
                                }

                                //если заявка снята (возможно ручками) или во время клиринга
                                if (ld.TradeList[i].OrderFromStopLimitOpenStatusOrder == cfg.Cancel)
                                {
                                    ld.TradeList[i].StopLimitOpenStatusOrder = null;
                                    ld.TradeList[i].OpenStatusOrder = null;
                                    ld.TradeList[i].OrderFromStopLimitOpenStatusOrder = null;
                                }
                            }
                        }
                    }

                }
            }
            catch
            { }
        }


        /// <summary>
        /// блок проверки стоп-заявок статуса и баланса на закрытие позиции
        /// </summary>
        /// <param name="ld"></param>
        public void GetStatusAndBalanceStopLimitClose(SterlingItem ld)
        {
            try
            {
                var orderMassiv = data.GetOrderListAll(ld.Account, ld.ClientCode);
                var StopLimitMassiv = data.GetStopOrderList(ld.Account, ld.ClientCode);


                #region Проверка по цене для стопа часть 1 из 3

                double StopPrice = GetStopPrice(ld);

                #endregion



                //Проверка исполнения заявки типа связанная заявка
                for (int i = 0; i < ld.TradeList.Count; i++)
                {
                    if (ld.TradeList.Count == 0)
                        break;

                    #region стоп лимит

                    foreach (var item2 in StopLimitMassiv)
                    {
                        //проверка статусов на изменение заявок на открытие пока балансе не равен выставленному числу
                        if (item2.TID == ld.TradeList[i].StopLimitCloseID &&
                            ld.TradeList[i].StopLimitCloseStatusOrder != cfg.Cancel &&
                            ld.TradeList[i].StopLimitCloseStatusOrder != cfg.Performed)
                        {
                            ld.TradeList[i].StopLimitCloseNumberOrder = item2.Number;
                            ld.TradeList[i].StopLimitCloseStatusOrder = item2.Status;
                        }
                        if (item2.TID == ld.TradeList[i].StopLimitCloseID)
                        {
                            if (ld.TradeList[i].StopLimitCloseStatusOrder != cfg.Unknown ||
                                String.IsNullOrEmpty(ld.TradeList[i].StopLimitCloseResult))
                                ld.TradeList[i].StopLimitCloseResult = item2.Result;
                            //если стоп-заявка отвергнута системой выставляем еще раз
                            if (ld.TradeList[i].StopLimitCloseResult == cfg.RemoveFormTs)
                                ld.TradeList[i].StopLimitCloseStatusOrder = null;
                            //определяем номер заявки выставленной в систему при активации стоп-заявки
                            if (ld.TradeList[i].StopLimitCloseResult == cfg.AddToTs)
                                ld.TradeList[i].StopLimitCloseNumberLinkidOrder = item2.NumberOrder;
                        }

                        

                        #region Проверка по цене для стопа часть 2 из 3

                        if (item2.TID == ld.TradeList[i].StopLimitCloseID &&
                            ld.TradeList[i].StopLimitCloseStatusOrder == cfg.Active)
                        {
                            //Проверка по цене активации
                            if (ld.TradeList[i].StopLimitCloseDate.TimeOfDay + new TimeSpan(0, 0, 10) <=
                                DateTime.Now.TimeOfDay)
                            {
                                if (item2.StopPrice != StopPrice)
                                {
                                    mainWindow.Terminals.CancelStopOrder(item2.Number, ld.Instrument, _classcode,
                                        ld.Account, ld.ClientCode);
                                    ld.TradeList[i].StopLimitCloseDate = DateTime.Now;
                                }
                            }
                        }

                        #endregion
                    }

                    //по прошествии 10 или уже другая дата секунд стоп-заявку можно снять снова, если не получилось с первого раза
                    if ((ld.TradeList[i].OrderFromStopLimitCloseDate.TimeOfDay + new TimeSpan(0, 0, 10) <=
                         DateTime.Now.TimeOfDay || ld.TradeList[i].OrderFromStopLimitCloseDate.Date != DateTime.Now.Date) &&
                        ld.TradeList[i].OrderFromStopLimitCloseDate != new DateTime())
                    {
                        ld.TradeList[i].OrderFromStopLimitCloseDate = new DateTime();
                    }

                    //если в течении 10 секунд стоп-заявка не появилась в системе удалить ее, или ее сняли в ручном формате и не было исполнения, или удаляетс из списка если заявка не определена и уже ее смотрят в другом дне. На закрытие позиции
                    if ((ld.TradeList[i].StopLimitCloseDate.TimeOfDay + new TimeSpan(0, 0, 10) <= DateTime.Now.TimeOfDay &&
                         ld.TradeList[i].StopLimitCloseStatusOrder == cfg.Unknown)
                        ||
                        (ld.TradeList[i].StopLimitCloseDate.Date != DateTime.Now.Date &&
                         (ld.TradeList[i].StopLimitCloseStatusOrder == cfg.Unknown)))
                    {
                        ld.TradeList[i].StopLimitCloseStatusOrder = null;
                    }
                    #endregion

                    //провереям заявки на выставление
                    if (ld.TradeList[i].StopLimitCloseStatusOrder != null &&
                        ld.TradeList[i].StopLimitCloseStatusOrder != cfg.Unknown)
                    {
                        foreach (var item2 in orderMassiv)
                        {
                            //проверка статусов на изменение заявок на закрытие позиции
                            if (ld.TradeList[i].StopLimitCloseID == item2.TID &&
                                ld.TradeList[i].CloseStatusOrder == null)
                            {
                                ld.TradeList[i].CloseStatusOrder = item2.Status;
                                ld.TradeList[i].CloseNumberOrder = item2.Number;
                                ld.TradeList[i].CloseID = item2.TID;
                            }

                            if (ld.TradeList[i].CloseStatusOrder != null && ld.TradeList[i].CloseID == item2.TID &&
                                ld.TradeList[i].StopLimitCloseNumberLinkidOrder == 0)
                                ld.TradeList[i].CloseStatusOrder = item2.Status;


                            if (ld.TradeList[i].StopLimitCloseResult == cfg.AddToTs)
                            {
                                if (ld.TradeList[i].StopLimitCloseNumberLinkidOrder == item2.Number &&
                                    ld.TradeList[i].OrderFromStopLimitCloseStatusOrder == null)
                                {
                                    ld.TradeList[i].OrderFromStopLimitCloseStatusOrder = item2.Status;
                                    ld.TradeList[i].OrderFromStopLimitCloseNumberOrder = item2.Number;
                                    ld.TradeList[i].OrderFromStopLimitCloseID = item2.TID;
                                }

                                if (ld.TradeList[i].OrderFromStopLimitCloseStatusOrder != null &&
                                    ld.TradeList[i].OrderFromStopLimitCloseID == item2.TID &&
                                    ld.TradeList[i].StopLimitCloseNumberLinkidOrder == item2.Number)
                                    ld.TradeList[i].OrderFromStopLimitCloseStatusOrder = item2.Status;

                                //если заявка снята (возможно ручками) исполнена в полном объеме
                                if (ld.TradeList[i].OrderFromStopLimitCloseStatusOrder == cfg.Performed)
                                {
                                    ld.TradeList.Remove(ld.TradeList[i]);
                                    if (i > 0)
                                        i--;
                                    if (i == 0)
                                        break;
                                }
                                //если заявка снята (возможно ручками) или во время клиринга
                                if (ld.TradeList[i].OrderFromStopLimitCloseStatusOrder == cfg.Cancel)
                                {
                                    ld.TradeList[i].StopLimitCloseStatusOrder = null;
                                    ld.TradeList[i].CloseStatusOrder = null;
                                    ld.TradeList[i].OrderFromStopLimitCloseStatusOrder = null;
                                }
                            }
                        }
                    }

                }
            }
            catch
            { }
        }
    }

}
